home *** CD-ROM | disk | FTP | other *** search
/ Nebula 2 / Nebula Two.iso / SourceCode / Flip / flip.c < prev    next >
C/C++ Source or Header  |  1995-06-12  |  14KB  |  564 lines

  1. /* ::[[ @(#) flip.c 1.18 89/07/04 16:07:16 ]]:: */
  2. #ifndef LINT
  3. static char sccsid[]="::[[ @(#) flip.c 1.18 89/07/04 16:07:16 ]]::";
  4. #endif
  5.  
  6. /*
  7. Copyright 1989 Rahul Dhesi, All rights reserved.
  8.  
  9. Checksum: 1217582374 (check or update with "brik")
  10. */
  11.  
  12. /*
  13. Does newline conversions between **IX and MS-DOS conventions.  Uses a state
  14. machine, so repeated conversions on the same file will do no harm.
  15. Assumes the US ASCII character set in some places (search for 'ASCII').
  16. */
  17.  
  18. /* change contents of flip.h as needed */
  19. #include "flip.h"
  20.  
  21. enum choices   { MSTOIX, IXTOMS, NEITHER };           /* conversion choices */
  22. enum state     { NONE, SAWCR, SAWLF, SAWCRLF, SAWCTRLZ };
  23.  
  24. void usage PARMS ((void));
  25. void give_help PARMS ((void));
  26. void flip_exit PARMS ((int));
  27. int getopt PARMS ((int argc, char **argv, char *options));
  28. void doarg PARMS ((char *, enum choices));
  29. int dofile PARMS ((char *, enum choices));
  30. char *nextfile PARMS ((int, char *, int));
  31. int ixtoms PARMS ((FILE *, FILE *));
  32. int mstoix PARMS ((FILE *, FILE *));
  33. void error PARMS ((char *, char *));
  34. void setup_sigs PARMS ((void));
  35. void cleanup PARMS ((int));
  36. char *mktemp PARMS ((char *));
  37.  
  38. #ifdef STDINCLUDE
  39. # include <stdlib.h>
  40. # include <string.h>
  41. #else
  42. void exit PARMS ((int));
  43. char *strcpy PARMS ((char *, char *));
  44. #endif
  45.  
  46. #ifdef NDEBUG
  47. # define assert(c)
  48. #else
  49. # ifdef STDINCLUDE
  50. #  include <assert.h>
  51. # else
  52. #  define assert(c)  if(!(c)) \
  53.                   fprintf(stderr,"assert error %s:%d\n",__FILE__,__LINE__)
  54. # endif /* STDINCLUDE */
  55. #endif /* NDEBUG */
  56.  
  57. #ifdef USE_TABLE
  58. char *bintab;
  59. #endif
  60.  
  61. #ifdef USE_SIG
  62. int got_sig;               /* will indicate if signal received */
  63. #endif
  64.  
  65. char *myname = NULL;
  66.  
  67. int exitstat = 0;          /* exit status */
  68. int verbose = 0;           /* set by -v option */
  69. int touch = 0;             /* set by -t option */
  70. int strip = 0;             /* set by -s option */
  71. int bintoo = 0;            /* set by -b option */
  72. int ztrunc = 0;            /* set by -z option */
  73. int filter = 0;           /* If no filenames given, act as filer */
  74.  
  75. main (argc, argv)
  76. int argc;
  77. char **argv;
  78.  
  79. {
  80.    int option;
  81.    extern int optind;
  82.    int i;
  83.    enum choices which = NEITHER;
  84. #ifdef USE_TABLE
  85. #define TABSIZ    256
  86.    char table[TABSIZ];
  87. #endif
  88.  
  89. #ifdef PICKNAME
  90.    register char *p; /* temp pointer for finding our name */
  91.    register char *arg0 = *argv;
  92. #endif /* PICKNAME */
  93.  
  94.    SPEC_INIT            /* optional initialization */
  95.  
  96. #ifdef USE_SIG
  97.    setup_sigs();
  98. #endif
  99.  
  100. #ifdef PICKNAME
  101. # define STRCMP(a,op,b)    (strcmp(a,b) op 0)
  102.    p = arg0 + strlen(arg0);
  103.  
  104.    if (p != arg0) {     /* if program name is defined */
  105.       while (p != arg0 && *p != '/' && *p != '\\')
  106.          p--;
  107.       assert ((p - arg0) <= strlen (arg0));
  108.       if (p != arg0)
  109.          p++;
  110.  
  111.       /* p now points to trailing name component, or nothing */
  112.       myname = p;
  113.       while (*p != '\0' && *p != '.') {   /* ASCII convert to lowercase */
  114.          if (*p >= 'A' && *p <= 'Z') {
  115.             *p = (*p - 'A' + 'a');
  116.          }
  117.          p++;
  118.       }
  119.       if (p != myname && *p == '.')
  120.          *p = '\0';     /* remove trailing .exe or .com under MS-DOS etc. */
  121.  
  122.       if (STRCMP(myname,==,"toix"))
  123.          which = MSTOIX;
  124.       else if (STRCMP(myname,==,"toms"))
  125.          which = IXTOMS;
  126.    } else
  127.    myname = "flip";
  128. #else
  129.    myname = "flip";
  130. #endif /* PICKNAME */
  131.  
  132. argv[0] = myname;                /* for use by getopt */
  133.  
  134. #ifdef USE_TABLE
  135. /* table to find out which characters are binary */
  136.    for (i = 0;  i < TABSIZ;  i++) {
  137.       if ( (i < 7) || (i > 13 && i < 26) || (i > 126)) /*ASCII binary chars*/
  138.          table[i] = 1;
  139.       else
  140.          table[i] = 0;
  141.    }
  142.    bintab = table;
  143. #endif /* USE_TABLE */
  144.  
  145.    if (argc < 2) {
  146.       usage();
  147.       flip_exit (1);
  148.    }
  149.  
  150.    while ((option = getopt (argc, argv, "umhvtsbz")) != EOF) {
  151.       switch (option) {
  152.        case 'u': which = MSTOIX;  break;
  153.        case 'm': which = IXTOMS; break;
  154.        case 'h': give_help(); flip_exit (0);
  155.        case 'v': verbose = 1;  break;
  156.        case 't': touch = 1;  break;
  157.        case 's': strip = 1;  break;
  158.        case 'b': bintoo = 1;  break;
  159.        case 'z': ztrunc = 1;  break;
  160.        default:  usage(); flip_exit (1);
  161.       }
  162.    }
  163.  
  164.    switch (which) {
  165.     case MSTOIX:
  166.       /* printf ("converting to **ix format\n"); */
  167.       break;
  168.     case IXTOMS:
  169.       /* printf ("converting to msdos format\n"); */
  170.       break;
  171.     default:
  172.       fprintf (stderr, "%s: error: -u or -m is required\n", myname);
  173.       flip_exit (1);
  174.       break;
  175.    }
  176.  
  177.    if (argc <= optind) {
  178.       /* fprintf (stderr, "%s: error: filenames are needed\n", myname);
  179.       flip_exit (1); */
  180.      filter=1;            /* We'll use stdin and stout instead */
  181.      switch (which) {
  182.      case IXTOMS:
  183.        exitstat = ixtoms (stdin, stdout);
  184.        break;
  185.      case MSTOIX:
  186.        exitstat = mstoix (stdin, stdout);
  187.        break;
  188.      }
  189.      return(exitstat);
  190.    }
  191.  
  192.    for (i = optind;  i < argc;  i++)
  193.       doarg (argv[i], which);
  194.  
  195.    return (exitstat);
  196. }
  197.  
  198.  
  199. /*
  200. Does conversion for one argument, calling dofile with wildcards
  201. expanded.  Updates exitstat in case of error.
  202. */
  203.  
  204. void doarg (arg, which)
  205. char *arg;
  206. enum choices which;
  207. {
  208. #ifdef WILDCARD
  209.    char *this_file;
  210.  
  211.    nextfile (0, arg, 0);
  212.    while ((this_file = nextfile(1, (char *) NULL, 0)) != NULL) {
  213.       exitstat |= dofile (this_file, which);
  214.    }
  215. #else
  216.    exitstat |= dofile (arg, which);
  217. #endif /* WILDCARD */
  218. }
  219.  
  220. #ifdef USE_SIG
  221. # include <signal.h>
  222. #endif
  223.  
  224. FILE *outfile;       /* make it visible to both dofile and cleanup */
  225.  
  226. /*
  227. Here we have filename and an option.  We call a different routine
  228. for each type of conversion.  This way more types of conversions
  229. can be easily added in the future.
  230. */
  231.  
  232. int dofile (fname, which)
  233. char *fname;
  234. enum choices which;
  235. {
  236.    FILE *infile;
  237.    char tfname[PATHSIZE];
  238.    SGFTIME timestamp;  /* save file timestamp here, restore later */
  239.    int errstat = 0;
  240.    char *p;             /* temp file ptr */
  241.  
  242. #ifdef USE_SIG
  243.    if (got_sig)
  244.       flip_exit (INT_EXIT);
  245. #endif
  246.  
  247.    /* if writable, open for reading */
  248.    if ((infile = fopen (fname, R_PL_B)) != NULL) {
  249.       fclose (infile);
  250.       infile = fopen (fname, RB);
  251.    }
  252.  
  253.    if (infile == NULL) {
  254.       error (fname, ": can't open");
  255.       return (1);
  256.    }
  257.  
  258.    /*
  259.    to make temp file in same dir as original, we make p point to the filename
  260.    component of fname, put '\0' there, and strcat the temp name to it
  261.    */
  262.    strcpy (tfname, fname);
  263.    p = tfname + strlen(tfname);
  264.  
  265.    while (p != tfname && *p != '/' && *p != '\\')
  266.       p--;
  267.    if (p != tfname)
  268.       p++;
  269.    *p = '\0';
  270.  
  271. #define  TEMPLATE    "XXXXXX"
  272.    {
  273.       char template[7];
  274.       strcpy (template, TEMPLATE);
  275.       strcat (tfname, mktemp (template));
  276.    }
  277.  
  278.    outfile = fopen (tfname, WB);
  279.  
  280.    if (outfile == NULL) {
  281.       fclose (infile);
  282.       error (fname, ": skipped, could not open temporary file");
  283.       return (1);
  284.    }
  285.  
  286.    if (!touch)
  287.       GETFT (infile, fname, timestamp);      /* save current timestamp */
  288.  
  289.    assert (which == IXTOMS || which == MSTOIX);
  290.  
  291. #ifdef BIGBUF
  292.    setvbuf (infile,  (char *) NULL, _IOFBF, BIGBUF);
  293.    setvbuf (outfile, (char *) NULL, _IOFBF, BIGBUF);
  294. #endif /* BIGBUF */
  295.  
  296.    switch (which) {
  297.     case IXTOMS:
  298.       errstat = ixtoms (infile, outfile);
  299.       break;
  300.     case MSTOIX:
  301.       errstat = mstoix (infile, outfile);
  302.       break;
  303.    }
  304.  
  305.    fclose (infile);
  306.  
  307.    switch (errstat) {
  308.     case ERRBINF:
  309.       fclose (outfile);
  310.       DELFILE (tfname);
  311.       fprintf (stderr, "%s: binary file, not converted\n", fname);
  312.       return (1);
  313.       /* break; */  /* unreachable code */
  314. #ifdef USE_SIG
  315.     case ERRSIG:
  316.       fclose (outfile);
  317.       DELFILE (tfname);
  318.       flip_exit (INT_EXIT);
  319.       break;
  320. #endif
  321.     default:
  322.       ;
  323.    }
  324.  
  325.    assert (errstat == 0);
  326.  
  327.    if (!ferror(outfile) && fflush(outfile) != EOF && fclose(outfile) != EOF) {
  328.       int moved;
  329.       DELFILE (fname);
  330.       moved = MVFILE (tfname, fname);
  331.       if (moved == 0) {
  332.          FILE *fptr;
  333.          if (!touch && (fptr = fopen (fname, RB)) != NULL) {
  334.             SETFT (fptr, fname, timestamp);
  335.             fclose (fptr);
  336.          }
  337.          if (verbose) {
  338.             printf ("%s\n", fname);
  339.             fflush (stdout);
  340.          }
  341.          return (0);
  342.       } else {
  343.          error (fname, ": not converted, could not rename temp file");
  344.          DELFILE (tfname);
  345.          return (1);
  346.       }
  347.    } else {
  348.       fclose (outfile); /* outfile was not closed, so close it here */
  349.       return (1);
  350.    }
  351. }
  352.  
  353. /* convert from ms-dos to **ix format */
  354. int mstoix (infile, outfile)
  355. FILE *infile;           /* input file   */
  356. FILE *outfile;          /* output file  */
  357. {
  358.    int c;
  359.    enum state state = NONE;
  360.  
  361.    /* lone LF => unchanged, lone CR => unchanged,
  362.       CR LF => LF, ^Z at end means EOF; ^Z elsewhere => unchanged */
  363.  
  364.    while (1) {       /* break out on EOF only */
  365.       while ((c = getc (infile)) != EOF) {
  366. #ifdef USE_SIG
  367.          if (got_sig)
  368.             return (ERRSIG);
  369. #endif
  370.          if (!bintoo && BINCHAR(c))
  371.             return (ERRBINF);
  372.          if (strip)
  373.             STRIP(c);
  374.          switch (c) {
  375.           case LF:
  376.             CHECK_BREAK
  377.             putc (c, outfile); if (state == SAWCR) state = NONE; break;
  378.           case CR:
  379.             state = SAWCR; break;
  380.           case CTRLZ:
  381.             if (state == SAWCR) putc (CR, outfile);
  382.             state = SAWCTRLZ; goto saweof;
  383.           default:
  384.             if (state == SAWCR) { state = NONE; putc (CR, outfile); }
  385.             putc (c, outfile);
  386.             break;
  387.          }
  388.       }
  389.  saweof:
  390.       /* exit outer loop only on EOF or ^Z as last char */
  391.       if (
  392.           ztrunc && state == SAWCTRLZ
  393.           || (c = getc (infile)) == EOF
  394.          )
  395.          break;
  396.       else
  397.          ungetc (c, infile);
  398.       if (state == SAWCTRLZ)
  399.          putc (CTRLZ, outfile);
  400.    }
  401.    return (0);
  402. }
  403.  
  404. /* convert from **ix to ms-dos format */
  405. int ixtoms (infile, outfile)
  406. FILE *infile;           /* input file   */
  407. FILE *outfile;          /* output file  */
  408. {
  409.    int c;
  410.    enum state state = NONE;
  411.  
  412.    /* LF => CR LF, but leave CR LF alone */
  413.    while ((c = getc (infile)) != EOF) {
  414. #ifdef USE_SIG
  415.       if (got_sig)
  416.          return (ERRSIG);
  417. #endif
  418.       if (!bintoo && BINCHAR(c))
  419.          return (ERRBINF);
  420.       if (strip)
  421.          STRIP(c);
  422.       switch (c) {
  423.        case LF:
  424.          CHECK_BREAK
  425.          if (state == SAWCR)
  426.             state = NONE;
  427.          else
  428.             putc (CR, outfile);
  429.          putc (LF, outfile);
  430.          break;
  431.        case CR:
  432.          state = SAWCR; putc (c, outfile); break;
  433.        case CTRLZ:
  434.          if (ztrunc)
  435.             return (0);
  436.          /* FALL THROUGH */
  437.        default:
  438.          state = NONE; putc (c, outfile); break;
  439.       }
  440.    }
  441.    return (0);
  442. }
  443.  
  444. /* set up signal handler for selected signals */
  445. #ifdef USE_SIG
  446. void setup_sigs ()
  447. {
  448. # ifdef SIGPIPE
  449.    if (signal (SIGPIPE, SIG_IGN) != SIG_IGN)
  450.       signal (SIGPIPE, cleanup);
  451. # endif
  452. # ifdef SIGHUP
  453.    if (signal (SIGHUP, SIG_IGN) != SIG_IGN)
  454.       signal (SIGHUP, cleanup);
  455. # endif
  456. # ifdef SIGQUIT
  457.    if (signal (SIGQUIT, SIG_IGN) != SIG_IGN)
  458.       signal (SIGQUIT, cleanup);
  459. # endif
  460. # ifdef SIGINT
  461.    if (signal (SIGINT, SIG_IGN) != SIG_IGN)
  462.       signal (SIGINT, cleanup);
  463. # endif
  464. # ifdef SIGTERM
  465.    if (signal (SIGTERM, SIG_IGN) != SIG_IGN)
  466.       signal (SIGTERM, cleanup);
  467. # endif
  468. }
  469.  
  470. /* set flag on signal */
  471. void cleanup(sig)
  472. int sig;
  473. {
  474.    signal (sig, SIG_IGN);     /* needed for flaky System V Release 2 */
  475.    got_sig = 1;
  476.    signal (sig, cleanup);     /* ditto */
  477. }
  478. #endif /* USE_SIG */
  479.  
  480. #define  ERRSIZE     200
  481.  
  482. /* prints error message via perror */
  483. void error (msg1, msg2)
  484. char *msg1, *msg2;
  485. {
  486.    char buf[ERRSIZE];
  487.    strcpy (buf, myname);
  488.    strcat (buf, ": ");
  489.    strcat (buf, msg1);
  490.    strcat (buf, msg2);
  491.    perror (buf);
  492.    fflush (stderr);
  493. }
  494.  
  495. /* gives brief usage message */
  496. void usage()
  497. {
  498.    fprintf (stderr,
  499. "usage:  %s [-u | -m] [other options] {files} (or \"%s -h\" for more help)\n",
  500.  myname, myname);
  501. }
  502.  
  503. /* gives help screen */
  504.  
  505. void give_help()
  506. {
  507. printf ("\
  508. File interchange program flip version 1.00.  Copyright 1989 Rahul Dhesi,\n\
  509. All rights reserved.  Both noncommercial and commercial copying, use, and\n\
  510. creation of derivative works are permitted in accordance with the\n\
  511. requirements of the GNU license.  This program does newline conversions.\n\
  512. (Filer capability added 3/12/92 by Craig Pratt)\n");
  513.  
  514. printf ("\n\
  515.    Usage:     flip -umhvtsbz file ...\n\
  516. \n\
  517. One of -u, -m, or -h is required;  others are optional.  See user manual.\n");
  518.  
  519. printf ("\n\
  520.    -u     convert to **IX format (CR LF => LF, lone CR or LF unchanged,\n\
  521.           trailing control Z removed, embedded control Z unchanged)\n\
  522.    -m     convert to MS-DOS format (lone LF => CR LF, lone CR unchanged)\n\
  523.    -h     give this help message\n\
  524.    -v     be verbose, print filenames as they are processed\n\
  525.    -t     touch files (don't preserve timestamps)\n\
  526.    -s     strip high bit\n\
  527.    -b     convert binary files too (else binary files are left unchanged)\n\
  528.    -z     truncate file at first control Z encountered\n\n\
  529.    When filenames are ommitted, flip uses standard input and output (CP 92)\n\
  530. ");
  531. #ifdef PICKNAME
  532. printf ("\n\
  533. May be invoked as \"toix\" (same as \"flip -u\") or \"toms\" (same as \"flip -m\").\n\
  534. ");
  535. #endif
  536. return;
  537. }
  538.  
  539. /* normal exits go through here -- atexit would be nice but not portable */
  540. void flip_exit(stat)
  541. int stat;
  542. {
  543.    SPEC_EXIT
  544.    exit (stat);
  545. }
  546.  
  547. /*
  548. special code for **IX -- not in use because can't properly handle
  549. SIGINT while /bin/mv is executing
  550. */
  551.  
  552. #ifdef NIX
  553. # ifndef MVFILE
  554. int MVFILE (src, dest)
  555. char *dest;
  556. char *src;
  557. {
  558.    char cmd[2 * PATHSIZE];
  559.    sprintf (cmd, "/bin/mv %s %s", src, dest);
  560.    return (system(cmd));
  561. }
  562. # endif /* MVFILE */
  563. #endif /* NIX */
  564.